package com.ke.rule.base;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 只在当前请求线程实现的缓存，请求完成后清除
 */
public class CacheLocalUtils {
  private static ThreadLocal<Map<String, Object>> caches = new ThreadLocal<Map<String, Object>>() {
    @Override
    protected Map<String, Object> initialValue() {
      return new HashMap<>();
    }
  };

  private static final Object NULL_VALUE = new Object();

  public static void shareCache(Map<String, Object> cache) {
    caches.set(cache);
  }

  public static Map<String, Object> getCacheMap() {
    return caches.get();
  }

  public static void set(String key, Object value) {
    caches.get().put(key, value);
  }
  
  @SuppressWarnings("unchecked")
  public static <T> T get(String key, Class<T> clazz) {
    return (T)caches.get().get(key);
  }
  
  public static Object get(String key) {
    return caches.get().get(key);
  }

  /**
   * 从缓存中获得对象，当对象不在缓存中，则返回 Supplier 回调产生的对象
   *
   * @param key      缓存的键
   * @param supplier 键不存在时的 回调方法，用于生产值对象
   * @param <T>      缓存的值类型
   * @return 缓存的结果
   */
  public static <T> T get(String key, Supplier<T> supplier) {
    Object result = get(key);
    if (result == null) {
      result = supplier.get();
      if (result == null) {
        result = NULL_VALUE;
      }
      set(key, result);
    }
    if (result.equals(NULL_VALUE)) {
      return null;
    }
    return (T) result;
  }
  
  /**
   * 存在缓存数据
   * @param key
   * @return
   */
  public static boolean contains(String key) {
    return caches.get().containsKey(key);
  }
  
  public static void clear() {
    caches.get().clear();
  }
  
  public static void clear(String key) {
    caches.get().remove(key);
  }
  
  public static int size() {
    return caches.get().size();
  }
  
  /**
   * 清除Key值匹配指定正则表达式的条目
   * @param pattern
   * @return
   */
  public static int clearByKeyPattern(String pattern) {
    Pattern p = Pattern.compile(pattern);
    
    Map<String, Object> m = caches.get();
    List<String> keys = m.keySet().stream().filter(k -> {
      return p.matcher(k).matches();
    }).collect(Collectors.toList());
    
    keys.forEach(k -> m.remove(k));
    return keys.size();
  }
}
